package service

import (
	"context"
	"fmt"
	"inventory/api/inventory"
	"inventory/internal/constant"
	"inventory/pkg/ecode"
	"inventory/pkg/util"

	"github.com/pkg/errors"
	"gorm.io/gorm"

	"inventory/internal/model"
)

// GetSelectionWarehouseStorageTypes 获取实时库存可选类别
func (s *Service) GetSelectionWarehouseStorageTypes(ctx context.Context,
	req *inventory.GetSelectionWarehouseStorageTypesRequest) (resp *inventory.GetSelectionWarehouseStorageTypesResponse, err error) {
	empId, sgId := req.WebToken.EmpId, req.WebToken.SgId
	if _, err = s.dao.GetWarehouseInfo(ctx, sgId, req.PStoreId, req.Id); err != nil {
		if errors.Cause(err) == gorm.ErrRecordNotFound {
			err = constant.ErrWarehouseNotExist
		}
		return
	}

	var views []*inventory.WarehouseStorageType
	switch req.Type {
	case inventory.StorageType_MATERIAL:
		if views, err = s.dao.GetWarehouseStorageTypes(ctx, sgId, req.Id); err != nil {
			return
		}
	case inventory.StorageType_PROD:
		var prodTypeIds []uint32
		if prodTypeIds, err = s.dao.GetWarehouseProductStorageTypes(ctx, empId, sgId, req.Id); err != nil {
			return
		}
		if len(prodTypeIds) != 0 {
			views, err = s.downstream.FetchProductTypes(ctx, empId, sgId, prodTypeIds)
		}
	default:
		err = ecode.BadRequest("Invalid type: %d", req.Type)
		return
	}
	resp = &inventory.GetSelectionWarehouseStorageTypesResponse{Types: views}
	return
}

// GetCommonExpressPlatforms 获取通用配送平台
func (s *Service) GetCommonExpressPlatforms(ctx context.Context, req *inventory.GetCommonExpressPlatformsRequest) (resp *inventory.GetPlatformsResponse, err error) {
	// 本接口不检查权限
	var expressPlatforms []*model.ExpressPlatform
	if expressPlatforms, err = s.dao.FindPlatformByMode(ctx, int(req.DeliverType)); err != nil {
		return
	}
	views := make([]*inventory.PlatformView, len(expressPlatforms))
	for i, p := range expressPlatforms {
		views[i] = &inventory.PlatformView{
			Id:   p.ID,
			Name: p.Name,
		}
	}
	resp = &inventory.GetPlatformsResponse{Platforms: views}
	return
}

// GetSelectionObject 查看库存操作可选产品/商品下拉框
func (s *Service) GetSelectionObject(ctx context.Context, req *inventory.GetSelectionObjectRequest) (resp *inventory.GetSelectionObjectResponse, err error) {
	var (
		total        int64
		data         []*inventory.GetSelectionInventoryType
		typeList     []string
		fetchStoreID uint32
	)
	sgId := req.WebToken.SgId
	if req.FetchStoreId != 0 {
		if req.PStoreId != 0 && req.FetchStoreId != req.PStoreId {
			err = ecode.BadRequest("当前模式不允许查询对应门店商品")
			return
		}
		fetchStoreID = req.FetchStoreId
	} else {
		fetchStoreID = req.PStoreId
	}
	dataMap := make(map[string][]*inventory.GetSelectionInventoryKey)
	switch req.StorageType {
	case inventory.StorageType_PROD:
		var prods []*inventory.ProdBomView
		if total, prods, err = s.downstream.FetchProductBom(ctx, sgId, req.PStoreId, fetchStoreID, req.PageNo,
			req.PageSize, req.IsConfigured, 0, req.FetchMode, req.Query, nil); err != nil {
			return
		}
		for _, prod := range prods {
			if _, ok := dataMap[prod.TypeName]; !ok {
				var keys []*inventory.GetSelectionInventoryKey
				dataMap[prod.TypeName] = keys
				typeList = append(typeList, prod.TypeName)
			}
			for _, sku := range prod.Skus {
				storageKey := fmt.Sprintf("%d-%d", prod.Id, sku.Id)
				dataMap[prod.TypeName] = append(dataMap[prod.TypeName], &inventory.GetSelectionInventoryKey{
					StorageKey:    storageKey,
					StorageName:   prod.Name,
					SkuName:       sku.Name,
					Code:          storageKey,
					Unit:          prod.Unit,
					StorageUnit:   prod.Unit,
					StorageRatio:  1,
					PurchaseUnit:  prod.Unit,
					PurchaseRatio: 1,
					PStoreId:      prod.PStoreId,
				})
			}
		}
	case inventory.StorageType_MATERIAL:
		var (
			materials       []*model.Material
			materialRemarks map[string]*model.FullRemark
		)
		if total, materials, err = s.dao.FindMaterialsByPage(ctx, sgId, req.PStoreId, fetchStoreID, int(req.FetchMode),
			int(req.PageNo), int(req.PageSize), req.Query); err != nil {
			return
		}
		materialIdMap := make(util.UInt64BoolMap)
		for _, m := range materials {
			materialIdMap[m.ID] = true
		}
		if materialRemarks, err = s.dao.BuildMaterialsRemarks(ctx, sgId, materialIdMap.GetKeys()); err != nil {
			return
		}
		for _, m := range materials {
			storageKey := fmt.Sprintf("m-%d", m.ID)
			remark := materialRemarks[storageKey]
			if _, ok := dataMap[remark.Type]; !ok {
				var keys []*inventory.GetSelectionInventoryKey
				dataMap[remark.Type] = keys
				typeList = append(typeList, remark.Type)
			}
			dataMap[remark.Type] = append(dataMap[remark.Type], &inventory.GetSelectionInventoryKey{
				StorageKey:    storageKey,
				StorageName:   remark.Name,
				SkuName:       remark.SkuName,
				Code:          remark.Code,
				Unit:          remark.Unit,
				StorageUnit:   remark.StorageUnit,
				StorageRatio:  remark.StorageRatio,
				PurchaseUnit:  remark.PurchaseUnit,
				PurchaseRatio: remark.PurchaseRatio,
				PStoreId:      remark.PStoreID,
			})
		}
	default:
		err = ecode.BadRequest("Invalid storage type: %d", req.StorageType)
		return
	}
	for _, typeName := range typeList {
		data = append(data, &inventory.GetSelectionInventoryType{
			TypeName: typeName,
			Keys:     dataMap[typeName],
		})
	}
	resp = &inventory.GetSelectionObjectResponse{
		Total: uint32(total),
		Data:  data,
	}
	return
}

// 获取当前模式下全量仓库列表
func (s *Service) GetSelectionWarehouse(ctx context.Context, req *inventory.GetSelectionWarehouseRequest) (
	resp *inventory.GetSelectionWarehouseResponse, err error) {
	if err = s.downstream.CheckAdmin(ctx, req.WebToken, req.PStoreId); err != nil {
		return
	}
	resp = &inventory.GetSelectionWarehouseResponse{
		Warehouses: make([]*inventory.SimpleWarehouseView, 0),
	}
	if !req.ReturnAll {
		if req.PStoreId == 0 {
			var warehouses []*model.Warehouse
			if warehouses, err = s.dao.FindAllHQWarehousesBySgID(ctx, req.WebToken.SgId); err != nil {
				return
			}
			for _, warehouse := range warehouses {
				resp.Warehouses = append(resp.Warehouses, &inventory.SimpleWarehouseView{
					Id:   warehouse.ID,
					Name: warehouse.Name,
				})
			}
		} else {
			var warehouse *model.Warehouse
			if warehouse, err = s.dao.GetWarehouseInfoByStoreID(ctx, req.PStoreId); err != nil {
				return
			}
			if warehouse.SgID != req.WebToken.SgId {
				err = constant.ErrWarehouseNotExist
				return
			}
			resp.Warehouses = append(resp.Warehouses, &inventory.SimpleWarehouseView{
				Id:   warehouse.ID,
				Name: warehouse.Name,
			})
		}
	} else {
		var warehouses []*model.Warehouse
		if _, warehouses, err = s.dao.FindWarehouses(ctx, req.WebToken.SgId,
			0, 0, 0); err != nil {
			return
		}
		for _, warehouse := range warehouses {
			resp.Warehouses = append(resp.Warehouses, &inventory.SimpleWarehouseView{
				Id:   warehouse.ID,
				Name: warehouse.Name,
			})
		}
	}
	return
}
